package server;

import com.lagou.http.HttpServlet;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * @author stevejson
 * 启动类
 */
public class Bootstrap {
    private int port = 8080;
    private String appBase;
    private Mapper mapper = new Mapper();

    public Mapper getMapper() {
        return mapper;
    }

    public void setMapper(Mapper mapper) {
        this.mapper = mapper;
    }

    public int getPort() {
        return port;
    }

    public String getAppBase() {
        return appBase;
    }

    public void setAppBase(String appBase) {
        this.appBase = appBase;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        //读取server.xml
        loadServerXML();
        //读取解析appBase下的web.xml
        loadAppBaseServlet();
        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

        ServerSocket serverSocket = new ServerSocket(port);

        System.out.println("miniCat start on Post: " + port);
        while (true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, this.mapper);
            threadPoolExecutor.execute(requestProcessor);
        }
    }
    private void loadServerXML() {
        InputStream inputStream = Bootstrap.class.getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Node portNode = rootElement.selectSingleNode("/Server/services/Connector/@port");
            this.port = Integer.parseInt(portNode.getStringValue());
            System.out.println("配置 port = " + this.port);

            Node appBaseNode = rootElement.selectSingleNode("/Server/services/Engine/Host/@appBase");
            this.appBase = appBaseNode.getStringValue();
            System.out.println("配置 appBase = " + this.appBase);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private  Map<String, HttpServlet> loadServlet(InputStream resourceAsStream, ClassLoader classLoader) {
        SAXReader saxReader = new SAXReader();
        try {
            Map<String, HttpServlet> servletMap = new HashMap<>();

            Document read = saxReader.read(resourceAsStream);
            Element rootElement = read.getRootElement();
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();

                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                // (HttpServlet) classLoader.loadClass(servletClass).newInstance()  Class.forName(servletClass).newInstance()
                servletMap.put(urlPattern, (HttpServlet) classLoader.loadClass(servletClass).newInstance());

            }
            return servletMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }
    private void loadAppBaseServlet() {
        File file = new File(this.appBase);
        for (File f : Objects.requireNonNull(file.listFiles())) {
            if (f.isDirectory()) {
                //f就是webapp下的子目录 demo01  demo02
                String webXmlFileName = f.getAbsolutePath() + "/WEB-INF/" + "web.xml";
                File webXmlFile = new File(webXmlFileName);
                if (webXmlFile.exists()) {
                    String fileName = f.getName();
                    try {
                        InputStream inputStream = new FileInputStream(webXmlFile);
                        //找到servlet 并且加载他，存储到Mapper中
                        Map<String, HttpServlet> stringHttpServletMap = this.loadServlet(inputStream, new MyClassLoader(f.getAbsolutePath()));
                        if (stringHttpServletMap != null){
                            this.mapper.putServletMap(fileName, stringHttpServletMap);
                        }

                    } catch ( FileNotFoundException e) {
                        e.printStackTrace();
                    }
                    this.mapper.putStaticResources(fileName, f.getAbsolutePath());
                }
            }
        }
    }
    public static void main(String[] args) throws Exception {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.start();
    }


}
